import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# 读取数据
data=pd.read_csv('data-simple.csv',sep=',', names=['user_id','item_id','rating'], header=0)


# 用户-物品矩阵
# m用户数  n商品数
m_users = data.user_id.nunique()
n_items = data.item_id.nunique()
print('item协同过滤推荐')
print('用户个数', m_users) # 返回不重复user_id的个数，统计用户的个数
print('物品个数', n_items) # 统计物品的个数

# 拆分数据集
from sklearn.model_selection import train_test_split
train_data, test_data =train_test_split(data,test_size=0.8) #按照训练集80%，测试集20%的比例对数据进行拆分
print('训练集80%   测试集20%')
# 用户-物品 矩阵
train_item_matrix = np.zeros((m_users,n_items))
for line in train_data.itertuples():
    train_item_matrix[line[1]-1,line[2]-1] = line[3]

# 构建物品相似矩阵 - 使用sklearn.metrics.pairwise中的cosine计算余弦距离
from sklearn.metrics.pairwise import pairwise_distances
# 相似度计算定义为 cosine 余弦距离
# euclidean 欧氏距离
item_similarity_m = pairwise_distances(train_item_matrix.T, metric='euclidean')

# 物品相似矩阵探索
# 现在我们只分析上三角，得到等分位数
item_similarity_m_triu = np.triu(item_similarity_m,k=1) # 取得上三角数据
item_sim_nonzero = np.round(item_similarity_m_triu[item_similarity_m_triu.nonzero()],3)

# 查看十分位数
# print('物品相似度十分位数', np.percentile(item_sim_nonzero, np.arange(0,101,10)))

# 训练集预测
user_item_precdiction = train_item_matrix.dot(item_similarity_m) / np.array([np.abs(item_similarity_m).sum(axis=1)])
# 除以np.array([np.abs(item_similarity_m).sum(axis=1)]是为了可以使评分在1~5之间，使1~5的标准化
# 只取数据集中有评分的数据集进行评估
from sklearn.metrics import mean_squared_error
from math import sqrt
prediction_flatten = user_item_precdiction[train_item_matrix.nonzero()]
user_item_matrix_flatten = train_item_matrix[train_item_matrix.nonzero()]
error_train = sqrt(mean_squared_error(prediction_flatten,user_item_matrix_flatten))  # 均方根误差计算
print('训练集预测均方根误差：', error_train)
# 测试集集预测
# 构建测试集评分矩阵
test_data_matrix = np.zeros((m_users,n_items))
for line in test_data.itertuples():
    test_data_matrix[line[1]-1,line[2]-1]=line[3]
item_prediction = test_data_matrix.dot(item_similarity_m) / np.array(np.abs(item_similarity_m).sum(axis=1))
# 只取数据集中有评分的数据集进行评估
prediction_flatten = user_item_precdiction[test_data_matrix.nonzero()]
test_data_matrix_flatten = test_data_matrix[test_data_matrix.nonzero()]
error_test = sqrt(mean_squared_error(prediction_flatten,test_data_matrix_flatten))  # 均方根误差计算
print('测试集预测均方根误差：', error_test)



